package com.ccsu.mymarket.jwt;

import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.ccsu.mymarket.exception.MyException;
import com.nimbusds.jose.*;
import com.nimbusds.jose.crypto.MACSigner;
import com.nimbusds.jose.crypto.MACVerifier;
import com.nimbusds.jwt.JWTClaimsSet;
import com.nimbusds.jwt.SignedJWT;
import lombok.extern.slf4j.Slf4j;

import java.text.ParseException;
import java.util.Date;
import java.util.Objects;

@Slf4j
public class JWTUtils {
    //    过期时间5分钟
    private static final long EXPIRE_TIME = 60 * 60 * 1000;
    public final static String KEY = "MIYAO";
    private static final byte[] SECRET = "6MNSobBRCHGIO0fS6MNSobBRCHGIO0fS".getBytes();

    /**
     * 使用 HS256算法对称加密生成 jwt token
     *
     * @param userId 用户 id
     * @return 生成的 jwt
     */
    public static String buildJWT(Integer userId)  throws MyException{
        if (userId == null){
            throw new MyException("加密时传入的id为空！");
        }
        try {
            /**
             * 1.创建一个32-byte的密匙
             */
            MACSigner macSigner = new MACSigner(SECRET);
            /**
             * 2. 建立payload 载体
             */
            JWTClaimsSet claimsSet = new JWTClaimsSet.Builder()
                    .subject("all")
                    .issuer("https://www.fishLi.com")
                    .expirationTime(new Date(System.currentTimeMillis() + EXPIRE_TIME))
                    .claim("ACCOUNT", userId)
                    .build();

            /**
             * 3. 建立签名
             *  需要加密后的 header 和加密后的 payload 使用.连接组成的字符串
             *  通过header中声明的加密方式进行 加盐secret 组合加密
             */
            SignedJWT signedJWT = new SignedJWT(new JWSHeader(JWSAlgorithm.HS256), claimsSet);
            signedJWT.sign(macSigner);

            /**
             * 4. 生成token
             */
            String token = signedJWT.serialize();

            return token;
        } catch (KeyLengthException e) {
            e.printStackTrace();
        } catch (JOSEException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 校验token
     *
     * @param token 加密的 token
     * @return 解密后的账户 id
     */
    public static Integer vaildToken(String token) throws MyException {
        if (token == null){
            throw new MyException("解析时传入了空的token");
        }
        try {
            SignedJWT jwt = SignedJWT.parse(token);
            JWSVerifier verifier = new MACVerifier(SECRET);
            //校验是否有效
            if (!jwt.verify(verifier)) {
                throw new MyException(-1, "Token 无效");
            }

            //校验超时
            Date expirationTime = jwt.getJWTClaimsSet().getExpirationTime();
            if (new Date().after(expirationTime)) {
                throw new MyException(-2, "Token 过期");
            }

            //获取载体中的数据
            Integer account = Integer.parseInt(String.valueOf(jwt.getJWTClaimsSet().getClaim("ACCOUNT")));
            //是否有openUid
            if (Objects.isNull(account)) {
                throw new MyException(-3, "token账号为空");
            }

            return account;
        } catch (ParseException e) {
            e.printStackTrace();
            throw new MyException("token格式错误，转换失败！");
        }catch (JOSEException e){
            e.printStackTrace();
            throw new MyException("解析器异常，转换失败！");
        }
    }

    //    以下暂时没用
    public static String buildJWT02(String userId) {
        Date date = new Date(System.currentTimeMillis() + EXPIRE_TIME);
        String token = "";
        token = JWT.create()
                .withAudience(userId) // 将 user id 保存到 token 里面
                .withExpiresAt(date) //五分钟后token过期
                .sign(Algorithm.HMAC256(KEY)); // token 的密钥
        return token;
    }

}
